package com.check.controller;

import com.check.CheckEnum;
import com.check.bean.DataList;
import com.check.bean.FileItem;
import com.check.bean.LoggerString;
import com.check.bean.UiList;
import com.check.dao.Dao;
import com.check.ui.Check;
import com.check.ui.CheckRuleStage;
import com.check.ui.Main;
import com.check.ui.StageModal;
import com.check.utils.*;
import com.github.crab2died.ExcelUtils;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.BorderPane;
import javafx.stage.FileChooser;
import javafx.stage.Stage;

import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @author zyt
 */
public class OneTableCheckController implements Initializable {

    private UiList uiList = UiList.getUIList();
    private DataList dataList = DataList.getDataList();
    private List<FileItem> fileItems = new ArrayList<>();
    private List<List<String>> lists;
    private List<List<String>> errList;
    private boolean qie = false;
    // 叠加显示的表
    private List<String> addList = new ArrayList<>();

    @FXML
    private ListView<String> listView;
    @FXML
    private TableView<List<StringProperty>> tableView1;
    @FXML
    private TableView<List<StringProperty>> tableView2;
    @FXML
    private Pagination pagination1;
    @FXML
    private Pagination pagination2;
    @FXML
    private Label label;

    public OneTableCheckController(){
        uiList.setOneTableCheckController(this);
    }

    @FXML
    private void toHome(){
        uiList.getHome().getStage().show();
        uiList.getMain().getStage().hide();
    }

    @FXML
    private void logger(){
        Stage stage = new Stage();
        BorderPane root = new BorderPane();
        //调用方法 添加多行文本框
        TextArea ta = new TextArea();
        root.setCenter(ta);
        Scene scene = new Scene(root,800,600);
        stage.setScene(scene);
        stage.setTitle("日志详情");
        ta.setText(LoggerString.stringBuffer.toString());
        stage.show();
    }

    /**
     * 清空已经生成的错误列表
     */
    @FXML
    private void clear(){
        final Check check = uiList.getCheck();
        if(check!=null){
            check.getStage().close();
        }
        uiList.setCheck(null);
        tableView2Clear(tableView2);
        if(errList!=null){
            errList = null;
        }
        pagination2.pageCountProperty().unbind();
        pagination2.setPageFactory(null);
        label.setText("");
        LoggerString.stringBuffer.append("清空已经生成的错误数据\n");
    }

    @FXML
    private void onCheck(){
        if(dataList.getHeads()==null){
            Alert alert = new Alert(Alert.AlertType.ERROR);
            alert.setTitle("检查错误");
            alert.setHeaderText("请先选择要检查的文件!");
            alert.setContentText("请先选择要检查的文件!");
            alert.showAndWait();
            return;
        }
        if(uiList.getCheck()==null){
            new Check().start(new Stage());
        }
        uiList.getCheck().getStage().show();
    }

    @FXML
    public void checkRule(){
        Stage stage =uiList.getCheckRuleStage();
        if(stage==null){
            stage = new CheckRuleStage();
        }
        stage.show();
    }

    /**
     * 从生成的错误中导出文件!
     */
    @FXML
    private void outPut(){
        if(errList==null || errList.size()<=1){
            Alert alert = new Alert(Alert.AlertType.ERROR);
            alert.setTitle("导出错误");
            alert.setHeaderText("生成检查文件错误!");
            alert.setContentText("错误条数为0或者没有生成检查文件!");
            alert.showAndWait();
            return;
        }

        try {
            File file = getFile("save");
            if (file == null)
                return;
            if(file.exists()){//文件已存在，则删除覆盖文件
                isDelete(file);
            }
            String exportFilePath = file.getAbsolutePath();
            String ends2 = ".xls";
            if (!file.getAbsolutePath().toUpperCase().endsWith(".xls".toUpperCase())) {
                // 如果文件不是以选定的拓展名结束的，则自动加上后缀
                exportFilePath = exportFilePath + ends2;
            }
            errList.get(0).add(label.getText());
            Stage stage = new StageModal("文件正在写入中,请稍后!");
            ExcelUtils.getInstance().exportObjects2Excel(errList,exportFilePath);
            LogUtils.appendLog("导出错误数据:文件路径-"+exportFilePath);
            LoggerString.stringBuffer.append("导出错误数据:"+exportFilePath+"\n");
            stage.close();
        } catch (IOException e) {
            Alert alert = new Alert(Alert.AlertType.INFORMATION);
            alert.setTitle("程序异常1001!请截图并联系开发人员!");
            alert.setContentText(e.getMessage());
            alert.showAndWait();
            e.printStackTrace();
        }
    }

    private boolean isDelete(File file) {
        return file.delete();
    }

    /**
     * 读取文件路径的对话框
     * @param type
     * @return
     */
    private File getFile(String type) {
        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("选择Excel文件");
        if (type.equals("save")){
            File cacheFile = new File(System.getProperty("user.home")+"/saveCache");
            readCache(fileChooser, cacheFile);
        } else if (type.equals("open")){
            File cacheFile = new File(System.getProperty("user.home")+"/openCache");
            readCache(fileChooser, cacheFile);
        } else {
            fileChooser.setInitialDirectory(new File(System.getProperty("user.home")));
        }
        fileChooser.getExtensionFilters().addAll(
                new FileChooser.ExtensionFilter("xls AllFiles (*.xls,*.xlsx)", "*.xls", "*.xlsx"),
                new FileChooser.ExtensionFilter("xls files (*.xls)", "*.xls"),
                new FileChooser.ExtensionFilter("xlsx files ,*.xlsx)", "*.xlsx")
        );
        Main main = uiList.getMain();
        Stage stage = main.getStage();
        File file;
        String filePath;
        if(type.equals("save")){
            file = fileChooser.showSaveDialog(stage);

        }else {
            file = fileChooser.showOpenDialog(stage);
        }
        filePath = file==null?"":file.getParent();
        if (type.equals("save") && !filePath.equals("")) {
            saveCache(new File(System.getProperty("user.home") + "/saveCache"),filePath);
        } else if (!filePath.equals("")) {
            saveCache(new File(System.getProperty("user.home") + "/openCache"),filePath);
        }
        return file;
    }

    /**
     * 向系统中写入缓存文件
     * @param cacheFile
     * @param path
     */
    private void saveCache(File cacheFile,String path){
        try(FileOutputStream out = new FileOutputStream(cacheFile)){
            out.write(path.getBytes());
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 从系统中读取缓存文件
     * @param fileChooser
     * @param cacheFile
     */
    private void readCache(FileChooser fileChooser, File cacheFile) {
        if (cacheFile.exists()){
            try(FileInputStream in = new FileInputStream(cacheFile)) {
                byte[] bytes = new byte[(int) cacheFile.length()];
                // Read the contents of the cache.txt
                in.read(bytes);
                File directory = new File(new String(bytes));
                if (directory.exists()) {
                    fileChooser.setInitialDirectory(directory);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @FXML
    private void clearImport(){
        // 获取选中
        final String selectedItem = listView.getSelectionModel().getSelectedItem();
        // 从ListView中删除选中
        listView.getItems().remove(selectedItem);
        listView.getSelectionModel().select(null);
        FileItem item = new FileItem();
        item.setName(selectedItem);
        // 从加载的文件列表中删除
        fileItems.remove(item);
        // 清空上下table
        tableView1Clear(tableView1);
        tableView2Clear(tableView2);
        // 清空叠加表
        addList.clear();
        this.lists = null;
        LoggerString.stringBuffer.append("删除导入文件:"+selectedItem+"\n");
    }

    private void tableView1Clear(TableView<List<StringProperty>> tableView1) {
        tableView1.getItems().clear();
        tableView1.getColumns().clear();
        pagination1.setPageFactory(param -> new Label());
        tableView1.refresh();
    }
    private void tableView2Clear(TableView<List<StringProperty>> tableView2) {
        tableView2.getItems().clear();
        tableView2.getColumns().clear();
        pagination2.setPageFactory(param -> new Label());
        tableView2.refresh();
    }

    /**
     * 导入文件,并将文件的路径以及文件的名字保存进fileItems中
     * 将文件名字导入到ListView中展示
     */

    @FXML
    private void importFile(){
        File file = getFile("open");
        if(file!=null){
            String path = file.getAbsolutePath();
            String name = file.getName();
            FileItem fileItem = new FileItem();
            fileItem.setName(name);
            fileItem.setPath(path);
            if (fileItems.contains(fileItem)){
                Alert alert = new Alert(Alert.AlertType.INFORMATION);
                alert.setTitle("该文件已经存在");
                alert.setContentText("该文件已经存在");
                alert.showAndWait();
                return;
            }
            fileItems.add(fileItem);
            String[] fileNames = ListUtils.fileItemsToStringArrays(fileItems);
            ObservableList<String> items = FXCollections.observableArrayList(fileNames);
            listView.setItems(items);
        }
    }

    public void tableViewInit1( List<List<String>> lists){
        List<String> columns = lists.get(0);
        final List<String> heads = columns.stream().map(StringUtils::trim).collect(Collectors.toList());
        dataList.setHeads(heads);
        this.label.setText("当前共有"+(lists.size()-1)+"条数据");
        loadTable(lists, heads,tableView1,pagination1);
    }

    private void loadTable(List<List<String>> lists, List<String> columns,TableView tableView1,Pagination pagination1) {
        tableView1.getColumns().clear();
        for (int i=0;i<columns.size();i++) {
            String column = columns.get(i);
            int a = i;
            TableColumn<List<StringProperty>,String> tableColumn= new TableColumn<>(column);
            tableColumn.setSortable(false);
            tableColumn.setCellValueFactory(data -> {
                if(data.getValue().size()<=a){
                    return new SimpleStringProperty("null");
                }
                return data.getValue().get(a);
            });
            // 设置列名字
            tableView1.getColumns().add(tableColumn);
            tableColumn.setMinWidth(100);
            if(column.equals("错误原因!")){
                tableColumn.setMinWidth(400);
            }
        }

        tableView1.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
        List<List<StringProperty>> data = new ArrayList();

        // 设置内容
        for (int i = 1; i < lists.size(); i++) {
            List<StringProperty> row = new ArrayList<>();
            for (int j = 0; j < lists.get(i).size() ; j++) {
                row.add(j, new SimpleStringProperty(lists.get(i).get(j)));
            }
            data.add(row);
        }
        // 分页大小
        Page<List<StringProperty>> page = new Page<>(data, 100);
        // 添加分页逻辑
        new TableWithPaginationAndSorting<>(page, tableView1, pagination1);
    }

    public void tableViewInit2(){
        tableView2Clear(tableView2);
        List<List<String>> data = checkData();
        String  str = "检查了" + (lists.size() - 1) + "个数据,错误数据有" + (errList.size() - 2) + "个";
        label.setText(str);
        LoggerString.stringBuffer.append(str+"\n");
        label.setMinWidth(str.length()*20);
        List<String> columns = data.get(0);
        loadTable(data, columns,tableView2,pagination2);
    }

    private List<List<String>> checkData() {
        Rule rule = new Rule();
        List<List<String>> errList = new ArrayList<>();
        Map<String, List<String>> map = dataList.getCheckMap();
        List<String> errHeads = new ArrayList<>(dataList.getHeads());
        List<String> errCount = new ArrayList<>();
        for(int i=0;i<dataList.getHeads().size();i++){
            errCount.add("");
        }
        // 给每一种错误都添加一个错误项
        map.forEach((k,v)->v.forEach(s->{
            errCount.add("0");
            errHeads.add("错误项");
        }));

        // 添加错误表头
        errList.add(errHeads);
        for (int i = 1; i < lists.size(); i++) {
            // 复制一行
            List<String> list =new ArrayList<>(lists.get(i));
            // 标记该行是否已经添加到错误数据列表中
            AtomicReference<Boolean> b = new AtomicReference<>(true);
            for (int j = 0; j < errHeads.size()-1; j++) {
                int emp = j;
                // 如果当前行的长度小于头的长度 就跳过该错误数据!不检查
                if(j>=list.size()){
                    break;
                }
                // 获取第i行第j列的数据-即检查的字符串
                String str = list.get(j);
                // 判断当前列是否拥有检查项
                // map中存储的是当前列表的检测要求数据!
                map.forEach((k,v)->{
                    // 获取当前数据对应的表头 并且与map的数据对应
                    if (k.equals(errHeads.get(emp))){
                        // 判断当前str 是否符合v中的多项检测标准!任何一项不符合都添加到errList里面
                        v.forEach((k1)-> {
                            int index = list.size();
                            if(index >= errCount.size()){
                                return;
                            }
                            Integer count = Integer.parseInt(errCount.get(index));
                            // 获取检测结果
                            String msg = check(errList, list, str, b, k1, rule);
                            // 将检测结果加入列表
                            if (msg.trim().isEmpty()){
                                list.add("");
                            }else {
                                list.add(errHeads.get(emp)+":"+msg);
                            }
                            if(msg.length()>0){
                                count++;
                            }
                            errCount.set(index,count.toString());
                        });
                    }
                });
            }
        }

        this.errList = errList;
        errList.add(errCount);
        this.removeNullError(errList,errCount);
        // 格式化数据
        return errList;
    }

    /**
     * 除去为0的错误项
     * @param errList
     * @param errCount
     */
    private void removeNullError(List<List<String>> errList, List<String> errCount) {
        List<Integer> indexList = new ArrayList<>();
        // 获取错误条数为0的列
        for (int i = 0; i < errCount.size(); i++) {
            if ("0".equals(errCount.get(i).trim())){
                indexList.add(i);
            }
        }
        // 从后往前删
        for (int i = 0; i < errList.size(); i++) {
            List<String> list = errList.get(i);
            for (int j = indexList.size()-1; j >= 0 ; j--) {
                list.remove(indexList.get(j).intValue());
            }
        }
    }

    private String check(List<List<String>> errList, List<String> list, String str, AtomicReference<Boolean> b, String k1,Rule rule) {
        CheckEnum checkEnum = CheckEnum.getByName(k1);
        if (checkEnum==null){
            return "";
        }
        return checkEnum.check(k1,str,errList,list,b,rule);
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        tableView1.setTableMenuButtonVisible(false);
        tableView2.setTableMenuButtonVisible(false);
        tableView1.setDisable(false);
        listView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
            if(qie) {
                qie = false;
                Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
                alert.setTitle("友情提示");
                alert.setHeaderText("你有未保存的叠加表,是否另存");
                alert.setContentText("另存点击确认,丢弃请选择取消!");
                Optional<ButtonType> result = alert.showAndWait();
                if (result.get() == ButtonType.OK) {
                    this.otherSave();
                }
            }
            addList.clear();
            if(newValue==null){
                return;
            }
            if(!newValue.equals(oldValue)){
                FileItem fileItem = ListUtils.findIndexByName(newValue,fileItems);
                addList.add(fileItem.getPath());
                try {
                    Stage stage = new StageModal("正在加载数据,请稍后!");
                    LogUtils.appendLog("从列表中加载文件到表格中:文件路径-"+fileItem.getPath());
                    LoggerString.stringBuffer.append("加载文件到表格:文件名-"+fileItem.getName()+"\n");
                    List<List<String>> lists = ExcelUtils.getInstance().readExcel2List(fileItem.getPath());
                    DataUtil.dataFormat(lists);
                    // 关闭检查界面
                    if (uiList.getCheck() != null){
                        uiList.getCheck().getStage().close();
                    }
                    this.lists = lists;
                    uiList.setCheck(null);
                    this.dao(lists);
                    this.tableViewInit1(this.lists);
                    stage.close();
                } catch (IOException e) {
                    Alert alert = new Alert(Alert.AlertType.INFORMATION);
                    alert.setTitle("程序异常1002!请截图并联系开发人员!");
                    e.printStackTrace();
                    alert.showAndWait();
                }
            }
        });
    }
    public void dao(List<List<String>> list){
        Dao dao = new Dao();

        if (list.get(0).size() == 8) {
            System.out.println("正在备份8......");
            new Thread(() -> {
                for (int i = 0; i < list.size(); i++) {
                    dao.addCopy2(list.get(i));
                }

            }).start();
        }
        if (list.get(0).size() == 39) {
            System.out.println("正在备份39......");
            new Thread(() -> {
                for (int i = 0; i < list.size(); i++) {
                    dao.addCopy1(list.get(i));
                }
            }).start();

        }
    }

    public boolean equalsList(List<String> list1,List<String> list2){
        if(list1.equals(list2)){
            return true;
        }
        if(list1.size()!=list2.size()){
            return false;
        }
        for (int i=0;i<list1.size();i++){
            if(!list1.get(i).equals(list2.get(i))){
                return false;
            }
        }
        return true;
    }

    @FXML
    public void addFile() {
        if (lists == null || lists.size()<=1){
            Alert alert = new Alert(Alert.AlertType.INFORMATION);
            alert.setTitle("请先加载要叠加的表格！");
            alert.showAndWait();
            return;
        }
        String select = listView.getSelectionModel().getSelectedItem();
        File file = getFile("open");
        if(file!=null){
            String path = file.getAbsolutePath();
            if (select.equals(path) || addList.contains(path)){
                Alert alert = new Alert(Alert.AlertType.INFORMATION);
                alert.setTitle("请不要重复添加！");
                alert.showAndWait();
                return;
            }
            try {
                List<List<String>> data = ExcelUtils.getInstance().readExcel2List(path, 0, 1, 0);
                DataUtil.dataFormat(data);
                List<String> newHead = data.get(0);
                List<String> oldHead = lists.get(0);
                if (equalsList(newHead,oldHead)){
                    qie = true;
                    Stage stage = new StageModal("正在加载数据,请稍后!");
                    LogUtils.appendLog("从列表中加载文件到表格中:文件路径-"+path);
                    data = ExcelUtils.getInstance().readExcel2List(path);
                    DataUtil.dataFormat(data);
                    addList.add(path);
                    this.dao(data);
                    data.addAll(lists.subList(1,lists.size()));
                    lists = DataUtil.dataFormat(data);
                    this.tableViewInit1(this.lists);
                    stage.close();
                }else{
                    Alert alert = new Alert(Alert.AlertType.INFORMATION);
                    alert.setTitle("提示");
                    alert.setContentText("你选择的表格格式不相同！");
                    alert.showAndWait();
                    return;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @FXML
    public void otherSave() {
        if(lists==null || lists.size()<=1){
            Alert alert = new Alert(Alert.AlertType.ERROR);
            alert.setTitle("另存错误");
            alert.setHeaderText("还没有选择或者已清空!");
            alert.setContentText("内容列表为零!");
            alert.showAndWait();
            return;
        }
        try {
            File file = getFile("save");
            if (file == null){
                return;
            }
            //文件已存在，则删除覆盖文件
            if(file.exists()){
                file.delete();
            }
            String exportFilePath = file.getAbsolutePath();
            String ends2 = ".xls";
            if (!file.getAbsolutePath().toUpperCase().endsWith(".xls".toUpperCase())) {
                // 如果文件不是以选定的拓展名结束的，则自动加上后缀
                exportFilePath = exportFilePath + ends2;
            }
            qie = false;
            Stage stage = new StageModal("文件正在写入中,请稍后!");
            ExcelUtils.getInstance().exportObjects2Excel(lists,exportFilePath);
            LogUtils.appendLog("另存数据:文件路径-"+exportFilePath);
            LoggerString.stringBuffer.append("另存数据:"+exportFilePath+"\n");
            stage.close();
        } catch (IOException e) {
            Alert alert = new Alert(Alert.AlertType.INFORMATION);
            alert.setTitle("程序异常1001!请截图并联系开发人员!");
            alert.setContentText(e.getMessage());
            alert.showAndWait();
            e.printStackTrace();
        }
    }
}